from PyQt5.QtWidgets import (QApplication, QButtonGroup, QRadioButton, QCheckBox, QComboBox,QTabWidget,QMessageBox,QTextEdit,QFrame,QAction,
                             QWidget, QLineEdit, QLabel, QPushButton, QFileDialog, QHBoxLayout, QGridLayout, QVBoxLayout, QListView)
from PyQt5.QtCore import Qt, QTimer, QBasicTimer, QDate, QAbstractListModel, QStringListModel, QEvent,pyqtSignal,QObject
from PyQt5.QtGui import QPixmap,QColor,QIcon,QMouseEvent

import sys
import traceback
from configUtils import *

class TabXMLToTS(QWidget):
    def __init__(self):
        super().__init__()
        self.moduleList = []
        self.setAcceptDrops(True)  # 接受拖放
        self.isSelectSearch = False
        self.tsInfMap = None
        curRow = 1

        # 关于 QGridLayout  https://blog.csdn.net/liang19890820/article/details/51538275
        self.mainBox = QGridLayout()
        self.mainBox.setAlignment(Qt.AlignTop)
        #self.mainBox.setColumnMinimumWidth(0,650)       
        self.setLayout(self.mainBox)

        self.padingLeft = 30
        self.padingTop = 50

        localConatainer = QWidget()
        hBox = QHBoxLayout()
        localConatainer.resize(300, 35)
        hBox.setAlignment(Qt.AlignTop)
        localConatainer.setLayout(hBox)
        self.mainBox.addWidget(localConatainer, curRow, 0)

        self.lblPath = QLabel()
        self.lblPath.setText("模块根目录：")
        #self.mainBox.addWidget(self.lblPath, curRow, 0)
        hBox.addWidget(self.lblPath,1)

       
        self.pathInput = QLineEdit() #模块根目录输入框
        self.pathInput.setPlaceholderText("模块目录")
        self.pathInput.textChanged.connect(self.onPathInputChange)
        py = self.pathInput.height()-self.lblPath.height()
        self.pathInput.move(
            self.lblPath.x()+self.lblPath.width()-30, self.lblPath.y()-5)
        #self.mainBox.addWidget(self.pathInput, curRow,1)
        hBox.addWidget(self.pathInput,20)
        

        self.btnBrowse = QPushButton()
        self.btnBrowse.setText("浏览")
        self.btnBrowse.setToolTip("浏览模块目录")        
        self.btnBrowse.clicked.connect(self.clickBtn)  # 注册点击事件
        #self.mainBox.addWidget(self.btnBrowse, curRow, 2)
        hBox.addWidget(self.btnBrowse,1)

        self.openBtn = QPushButton()
        self.openBtn.setText("打开")
        self.openBtn.setToolTip("打开项目的模块目录")        
        self.openBtn.clicked.connect(self.clickBtn)  # 注册点击事件
        #self.mainBox.addWidget(self.btnBrowse, curRow, 2)
        hBox.addWidget(self.openBtn,1)

        self.lblSearch = QLabel()
        self.lblSearch.setText("模块名:")           
        #self.mainBox.addWidget(self.lblSearch, curRow, 3)
        hBox.addWidget(self.lblSearch,1)

        self.searchInput = QLineEdit()
        self.searchInput.textChanged.connect(self.onSearchInputChange)
        self.searchInput.installEventFilter(self)
        self.searchInput.setPlaceholderText("保存TS的目录")
        self.searchInput.setToolTip(
            "不填则以模块根目录作为TS保存目录，否则以该目录作为保存路径（没有目录会自动创建）")
        #self.mainBox.addWidget(self.searchInput,curRow,4)
        hBox.addWidget(self.searchInput,10)

        self.checBox = QCheckBox()
        self.checBox.setText("忽略模块名保存TS")
        self.checBox.setToolTip("勾选后以模块根目录作为TS保存目录")
        #self.mainBox.addWidget(self.checBox, curRow, 5)
        hBox.addWidget(self.checBox,1)

        curRow += 1

        localConatainer = QWidget()
        hBox = QHBoxLayout()
        localConatainer.resize(300, 35)
        hBox.setAlignment(Qt.AlignTop)
        localConatainer.setLayout(hBox)
        self.mainBox.addWidget(localConatainer,curRow,0)

        self.model = QStringListModel(self)
        #self.model.setStringList(["a", "b", "c", "d"])

        lblName = QLabel()
        lblName.setText("类名:")
        #self.mainBox.addWidget(lblName, curRow, 0)
        hBox.addWidget(lblName,1)

        self.lblClsName = QLineEdit()
        self.lblClsName.setPlaceholderText("输入要生成的类名")
        #self.mainBox.addWidget(self.lblClsName, curRow, 1)
        hBox.addWidget(self.lblClsName,4)
        #hBox.setStretchFactor(self.lblClsName,12)

        lblName = QLabel()
        lblName.setText("类注释:")
        #self.mainBox.addWidget(lblName, curRow, 0)
        hBox.addWidget(lblName,1)

        self.annotationCls = QLineEdit()
        self.annotationCls.setPlaceholderText("输入类注释")
        #self.mainBox.addWidget(self.lblClsName, curRow, 1)
        hBox.addWidget(self.annotationCls,3)
        #hBox.setStretchFactor(self.annotationCls,8)

        lblName = QLabel()
        lblName.setText("选择父类:")        
        #self.mainBox.addWidget(lblName, curRow, 2)
        hBox.addWidget(lblName,1)

        self.ListRenderer = "ListRenderer"
        self.ModuleClsName = "BaseModule"
        self.baseClsList = getTempList()
        
        self.comBox = QComboBox()
        self.comBox.setGeometry(200, 50, 150, 30)
        self.comBox.activated[str].connect(self.onSelectBaseCls)
        self.comBox.addItems(self.baseClsList)
        self.curBaseCls = self.baseClsList[0]

        #self.setClsText()
        #self.mainBox.addWidget(self.comBox, curRow, 3)
        hBox.addWidget(self.comBox,2)

        lblName = QLabel(localConatainer)
        lblName.setText("字段属性:")
        hBox.addWidget(lblName, 1)

        privateBtn = QRadioButton()
        privateBtn.setText("private")
        hBox.addWidget(privateBtn, 1)

        protectedBtn = QRadioButton()
        protectedBtn.setText("protected")
        #protectedBtn.setChecked(True)
        hBox.addWidget(protectedBtn, 1)
        
        publicBtn = QRadioButton()
        publicBtn.setText("public")
        hBox.addWidget(publicBtn,1)

        # 字段限定名 按钮组
        self.varProGroup = QButtonGroup()
        self.varProGroup.addButton(privateBtn)
        self.varProGroup.addButton(protectedBtn)
        self.varProGroup.addButton(publicBtn)
        self.varProGroup.buttonClicked.connect(self.radioBtnClick)
        
        curRow += 1
        
        localConatainer = QWidget()
        hBox = QHBoxLayout()
        localConatainer.resize(300, 35)
        hBox.setAlignment(Qt.AlignTop)
        localConatainer.setLayout(hBox)
        self.mainBox.addWidget(localConatainer, curRow,0)

        self.startBtn = QPushButton()
        self.startBtn.setText("开　始")        
        self.startBtn.clicked.connect(self.onClickStart)
        #self.mainBox.addWidget(self.startBtn, curRow, 0)
        hBox.addWidget(self.startBtn,1)

        self.btnClickEvtCb = QCheckBox()
        self.btnClickEvtCb.setText("自动为按钮添加点击事件")
        self.btnClickEvtCb.setToolTip("为所有按钮添加点击事件")
        #self.mainBox.addWidget(self.btnClickEvtCb, curRow, 1)
        hBox.addWidget(self.btnClickEvtCb,1)

        self.listEvtCb = QCheckBox()
        self.listEvtCb.setText("自动为List添加选择事件")
        self.listEvtCb.setToolTip("为所有List添加点击事件")
        #self.mainBox.addWidget(self.listEvtCb, curRow, 2)
        hBox.addWidget(self.listEvtCb,1)
        
        self.ctrlEvtCb = QCheckBox()
        self.ctrlEvtCb.setText("自动为controller添加选择事件")
        self.ctrlEvtCb.setToolTip("为所有controller添加点击事件")
        #self.mainBox.addWidget(self.listEvtCb, curRow, 2)
        hBox.addWidget(self.ctrlEvtCb,3)

        curRow += 1

        self.logText = QTextEdit()        
        #self.logText.setFocusPolicy(Qt.NoFocus)
        #self.logText.setReadOnly(True)
        self.logText.setAcceptDrops(False)
        self.logText.setFontWeight(30)
        self.logText.viewport().installEventFilter(self)
        #self.logText.cursorPositionChanged.connect(self.onLogPo)
        #self.logText.clicked.connect(self.logClick)
        #self.logText.setAttribute(Qt.WA_NoMousePropagation,False)
        self.logText.setPlaceholderText("日志输出")
        self.mainBox.addWidget(self.logText,curRow,0,1,1)

        self.searchResult = QListView(self)
        self.searchResult.resize(200, 200)
        self.searchResult.setModel(self.model)       
        self.searchResult.clicked.connect(self.selectSearch)
        self.searchResult.setVisible(False)

        self.padding = "    "        
        self.curXmlUrl = False
        self.updateSetting()
        self.setClsText()

    def onLogPo(self,*arg):
        print("onLogPo",arg)

    def updateSetting(self):         
        fileName = getToolCfg(EToolCfg.modulePath.name)
        self.pathInput.setText(fileName)
        self.initModuleList(fileName)

        index = getToolCfg(EToolCfg.fieldPro.name)
        btns = self.varProGroup.buttons()
        index = min(index,len(btns)-1)
        self.proBtn = protectedBtn = btns[index]
        self.proBtn.setChecked(True)

        mName = getToolCfg(EToolCfg.moduleName.name)
        self.searchInput.setText(mName)

        flag = bool(getToolCfg(EToolCfg.autoBtn.name))
        self.btnClickEvtCb.setChecked(flag)

        flag = bool(getToolCfg(EToolCfg.autoList.name))
        self.listEvtCb.setChecked(flag)

        flag = bool(getToolCfg(EToolCfg.autoCtrl.name))
        self.ctrlEvtCb.setChecked(flag)
        
    def logClick(self,e):
        print("-----logClick",e)

    def isBaseList(self):
        """当前基类是否是 ListRenderer 
        """
        return self.curBaseCls==self.ListRenderer

    def isBaseModule(self):
        """当前基类是否是 BaseModule 
        """
        return self.curBaseCls==self.ModuleClsName or self.curBaseCls=="BaseTabModule"

    def onSelectBaseCls(self,text):
        #print("onSelectBaseCls",text)
        self.curBaseCls = text
        self.setClsText()
        self.curTemp = getTemp(self.curBaseCls) #当前基类的模板代码

    def setClsText(self):
        oldStr = str(self.lblClsName.text())
        fix = "UI_"
        if oldStr.startswith(fix) or oldStr=="" or not self.isClsNameOk(oldStr):
            clsName = self.getBaseClsEnd(self.curBaseCls)        
            clsName = fix+self.curBaseCls if clsName==self.curBaseCls else clsName
            self.lblClsName.setText(clsName)

        if not self.isBaseModule() and self.curXmlUrl and os.path.isfile(self.curXmlUrl): #当前基类是ListRender 类名直接是 xml文件名
            content = os.path.split(self.curXmlUrl)[1].split(".")[0]
            self.lblClsName.setText(content)
        else:
            clsName = self.getBaseClsEnd(self.curBaseCls)        
            clsName = fix+self.curBaseCls if clsName==self.curBaseCls else clsName
            self.lblClsName.setText(clsName)

    def getBaseClsEnd(self,clsName):
        """根据基类名称获取基类的后缀名称
        例如： BaseTabPanel 会得到 Panel
        
        Arguments:
            clsName {[str]} -- [基类名称]
        """
        n = len(clsName)
        if self.isLegalModule():            
            for i in range(n):
                idx = n-i-1
                char = clsName[idx]  #从字符串的后面开始找          
                if char.istitle(): #找到第一个大写字母
                    clsName = self.getTitleStyle(self.searchInput.text()) + clsName[idx:]                
                    break
        return clsName

    def onClickStart(self,e):        
        if self.pathInput.text()!="" and os.path.isdir(self.pathInput.text()):
            checked = self.checBox.isChecked() 
            if checked or self.isLegalModule():                
                curClsName = self.lblClsName.text()
                if not self.isClsNameOk(curClsName):
                    QMessageBox.information(self,"提示","类名只能包含字母、下划线、数字")
                    return
                if self.tsInfMap:
                    if self.curTemp and curClsName!="":                    
                        self.curClsName = curClsName #当前生成的类名 也是文件名
                        try:
                            self.makeTsFile()
                        except Exception as e:
                            self.appendLog("创建文件发生异常了-_- :")
                            self.appendLog(traceback.format_exc())
                            
                else:
                    QMessageBox.information(self,"提示","请把GUI的XML文件拖进来")                    
                #self.tsInfMap = None
            else:
                QMessageBox.warning(self,"警告","模块名只能纯字母")
        else:            
            # 参数顺序：标题，msg，按钮排列顺序，默认焦点按钮
            replay = QMessageBox.question(self,"系统提示","请先设置模块路径",QMessageBox.Yes,QMessageBox.Yes)
        setToolCfg(EToolCfg.moduleName.name,self.searchInput.text())

    def isClsNameOk(self,clsName):
        mobj = regClsName.match(clsName)
        return mobj!=None 

    def radioBtnClick(self, btn):
        self.proBtn = btn

    def eventFilter(self, watch, event): #事件监听器;需要通过 installEventFilter 注册
        if watch == self.searchInput:
            if event.type() == QEvent.FocusOut:
                pass               
            elif event.type() == QEvent.FocusIn:
                #print("搜索输入框得到焦点",self.searchInput.x())
                self.showSearchResult(True)      
        elif watch == self.logText.viewport() and isinstance(event,QMouseEvent) and event.type()==QMouseEvent.MouseButtonRelease:                    
            self.searchResult.setVisible(False)
        return super().eventFilter(watch, event)

    def mousePressEvent(self,e):
        #print("mousePressEvent ", e, time.time())        
        self.searchResult.setVisible(False)

    def dragEnterEvent(self, e):  # 拖拽进入区域
        if e.mimeData().hasUrls():  
            e.accept()

    def dropEvent(self, e):  # 放开了        
        url = e.mimeData().text()
        fileType = os.path.splitext(url)[1]
        url = str(url).replace("file:///", "")
        print("url",url)
        self.curXmlUrl = url
        self.appendLog(self.curXmlUrl)
        if fileType == ".xml": #把xml转换成Python对象
            self.tsInfMap = xmlToTsInf(url)
            self.curTemp = getTemp(self.curBaseCls)
            
    def onSearchInputChange(self, *args):        
        if not self.isSelectSearch:
            self.showSearchResult(False)
        self.isSelectSearch = False

    def onPathInputChange(self):
        fileName = self.pathInput.text()
        self.initModuleList(fileName,True)

    def showSearchResult(self, isAll):
        text = self.searchInput.text()
        strList = []
        hasRet = True
        if not isAll:
            isAll = len(text)==0
        if isAll:
            strList = self.moduleList
        else:
            if len(text) > 0:
                for s in self.moduleList:
                    idx = str(s).lower().find(text.lower())
                    if idx == 0:
                        strList.append(s)        
        self.searchResult.setVisible(hasRet)
        if hasRet:               
            gPos = self.searchInput.parent().mapToGlobal(self.searchInput.pos())
            gPos = self.mapFromGlobal(gPos)                   
            self.searchResult.move(gPos.x(),gPos.y()+self.searchInput.height())
            #self.searchResult.move(self.searchInput.x(),self.searchInput.y()+self.searchInput.height())
        self.model.setStringList(strList)

    def selectSearch(self, modelIndex):  # PyQt5.QtCore.QModelIndex
        data = self.model.itemData(modelIndex)
        if data and data[0] and len(data[0]) > 0:
            self.isSelectSearch = True
            self.searchInput.setText(data[0])
            self.setFocus()
            self.searchResult.setVisible(False)

    def clickBtn(self, *arg):
        btn = self.sender()
        if btn==self.btnBrowse:
            self.browse()
        elif btn==self.openBtn and os.path.isdir(self.pathInput.text()):
            os.startfile(self.pathInput.text())

    def browse(self):
        #print("点击按钮了....", arg)
        #fileName,fileType = QFileDialog.getOpenFileName(self,"选中模块根目录")
        fileName = QFileDialog.getExistingDirectory(
            self, "选中模块根目录",getToolCfg(EToolCfg.modulePath.name)) #"E:/H5Game/Client/src/game/module"        

        self.setFocus()          
        self.initModuleList(fileName,True)

    def initModuleList(self, fileName,isSaveCfg=False):
        """初始化模块搜索列表
        
        Arguments:
            fileName {[str]} -- [模块根目录]
        
        Keyword Arguments:
            isSaveCfg {bool} -- [是否保存设置] (default: {False})
        """
        if os.path.exists(fileName) and os.path.isdir(fileName):
            if isSaveCfg: #是否保存配置
                setToolCfg(EToolCfg.modulePath.name,fileName)
            self.pathInput.setText(fileName)
            self.moduleList = [file for file in os.listdir(fileName) if not file.startswith(
                ".") and os.path.isdir(os.path.join(fileName, file))]
            if self.searchResult.isVisible():
                self.showSearchResult(False)
                
    def mkTempClassStr(self,tempClsStr,mkClassName,varStr,fnBodyStr,funcStr,clsDesc=""):
        """生成类模板代码
        
        Arguments:
            tempClsStr {str} -- [原始的类模板代码字符串]
            mkClassName {str} -- [要生成的类名]
            varStr {str} -- [字段定义字符串]
            fnBodyStr {str} -- [初始化UI的函数体字符串]
            funcStr {str} -- [所有监听函数字符串]
            clsDesc {str} -- [类注释]
        """
        tempClsStr = tempClsStr.replace(r"$cls$",mkClassName)
        m = self.getModuleName()
        tempClsStr = tempClsStr.replace(r"$module$",m) #生成模块名
        clsDesc = self.annotationCls.text() if clsDesc=="" else clsDesc
        tempClsStr = tempClsStr.replace(r"$desc$",clsDesc) #生成注释
        authorStr = getToolCfg(EToolCfg.author.name) #
        if not authorStr:
            authorStr = "[by H5Gui create]"                    
        tempClsStr = tempClsStr.replace(r"$author$",authorStr) #生成作者
        now = time.time()
        nowArr =  time.localtime(now) #把时间戳转换成时间数组
        nowStr = time.strftime("%Y-%m-%d %H:%M:%S")  #把时间数组格式化为时间字符串
        tempClsStr = tempClsStr.replace(r"$time$",nowStr) #生成时间
        content = os.path.split(self.curXmlUrl)[1].split(".")[0]
        tempClsStr = tempClsStr.replace(r"$contentName$",content) #生成UI组件名称
        tempClsStr = tempClsStr.replace(r"$var$",varStr)
        tempClsStr = tempClsStr.replace(r"$fnBody$",fnBodyStr)
        tempClsStr = tempClsStr.replace(r"$func$",funcStr)
        return tempClsStr

    def makeTsFile(self):
        """创建用户主动要求的TS类文件
        """
        st = time.time()        
        #要生成的显示对象类型；按照顺序生成在代码里
        orderType = [EDisplayType.controller,EDisplayType.group,EDisplayType.baseitem,EDisplayType.loader,EDisplayType.image,EDisplayType.text,EDisplayType.richtext,EDisplayType.Button,EDisplayType.list]
        count = len(orderType)        
        newLine = "\r"
        varStr = ""
        fnStr = self.padding*2+"//---- script make start ----"+newLine
        btnClickStr = ""
        listSelectStr = ""
        ctrlClickStr = ""
        for i in range(count):
            varArr = self.tsInfMap[orderType[i].name]
            if varArr and len(varArr)>0:
                for xml in varArr:                    
                    vs,fs = self.xmlToVarFnStr(xml)
                    varStr += vs+newLine
                    fnStr += fs+newLine
                    #生成 addEventListener 字符串
                    if xml.name == EDisplayType.Button.name and self.btnClickEvtCb.isChecked():
                        tempStr = self.padding*2+"this."+self.getFieldName(xml.attr['name'])+"."+getFuncName("addClickListener")+"(this.{0}, this);"+newLine              
                        btnClickStr+=tempStr.format(getFnTempName(EFnTemp.btnFn.name))
                    elif xml.name == EDisplayType.list.name and self.listEvtCb.isChecked():     
                        tempStr = self.padding*2+"this."+self.getFieldName(xml.attr['name'])+".list.addEventListener(fairygui.ItemEvent.CLICK,this.{0},this);"+newLine                
                        listSelectStr+=tempStr.format(getFnTempName(EFnTemp.listFn.name))
                    elif xml.name == EDisplayType.controller.name and self.ctrlEvtCb.isChecked():
                        tempStr = self.padding*2+"this."+self.getFieldName(xml.attr['name'])+".addEventListener(fairygui.StateChangeEvent.CHANGED, this.{0}, this);"+newLine
                        ctrlClickStr += tempStr.format(getFnTempName(EFnTemp.ctrlFn.name))
                    
        fnStr += newLine + ctrlClickStr + btnClickStr + listSelectStr
        fnStr += self.padding*2+"//---- script make end ----"+newLine        
        #按钮和list侦听函数字符串
        ctrlFuncStr = ""
        if ctrlClickStr:
            ctrlFuncStr = self.getClickEvtFnStr(EFnTemp.ctrlFn.name,EDisplayType.controller.name,"")+newLine

        btnFuncStr = ""
        if btnClickStr != "":            
            btnFuncStr = self.getClickEvtFnStr(EFnTemp.btnFn.name,EDisplayType.Button.name,"")+newLine

        listFuncStr = ""
        if listSelectStr!="":
            listFuncStr = self.getClickEvtFnStr(EFnTemp.listFn.name,EDisplayType.list.name,".list")+newLine
        
        funcStr = ctrlFuncStr + btnFuncStr + listFuncStr
        self.curMakeClsStr = self.mkTempClassStr(self.curTemp,self.curClsName,varStr,fnStr,funcStr)

        fileName = self.curClsName+".ts"
        moduleName = "" if self.checBox.isChecked() else self.searchInput.text()
        modulePath = self.pathInput.text() #模块根目录
        folder = os.path.join(modulePath,moduleName) #完整的某个模块目录
        isCreateModule = False
        if self.createModuleFolder(folder):    
            isCreateModule = True        
            self.initModuleList(modulePath)

        if (self.isBaseModule() or isCreateModule) and moduleName!="": #检测是否有proxy和controller 没有自动创建
            flag = bool(getToolCfg(EToolCfg.autoMkProxy.name))
            if flag:                
                self.createFnClass(folder,moduleName,"Proxy",EFnTemp.proxy.name,"模块代理类")
            flag = bool(getToolCfg(EToolCfg.autoMkCtrl.name))
            if flag:                
                self.createFnClass(folder,moduleName,"controller",EFnTemp.controller.name,"模块控制器")
            flag = bool(getToolCfg(EToolCfg.autoMkCache.name))
            if flag:                
                self.createFnClass(folder,moduleName,"Cache",EFnTemp.cache.name,"模块数据缓存")

        fileName = os.path.join(folder,fileName)
        flag = self.createClassFile(fileName,self.curClsName,self.curMakeClsStr)        
        if flag:
            ct = time.time() - st
            ctStr = "耗时%0.5f秒"%(ct)      
            self.appendLog("已经生成 "+fileName+" {0}".format(ctStr))

    def createFnClass(self,moduleFolder,moduleName,fixClsName,eFnTempName,clsDesc)->bool:
        """创建其他功能类(proxy或controller)
        
        Arguments:
            moduleFolder {[str]} -- [模块目录]
            moduleName {[str]} -- [模块名称]
            fixClsName {[str]} -- [类后缀]
            eFnTempName {[str]} -- [类模板名称]
            clsDesc {[str]} -- [类注释]
        
        Returns:
            bool -- [是否创建成功]
        """        
        clsModuleStr = self.curClsName if self.curClsName and self.curClsName.lower().find("module")!=-1 else moduleName.title()+"Module" #用index查找字符串 找不到会报错:substring not found
        fnClsName = self.getClsNameByModule(moduleName,fixClsName)
        fileName = os.path.join(moduleFolder,fnClsName+".ts")
        flag = False        
        if not os.path.exists(fileName):            
            fnTemp = getFnTemp(eFnTempName)
            fnClsStr = self.mkTempClassStr(fnTemp,fnClsName,"","","",clsDesc)
            fnClsStr = fnClsStr.replace("$clsModule$",clsModuleStr)
            flag = self.createClassFile(fileName,fnClsName,fnClsStr)
        if flag:
            self.appendLog("已为你创建{0}类在:{1}".format(fnClsName,fileName))
        return flag   

    def getClsNameByModule(self,moduleName,fixName):
        moduleNameTitle = moduleName
        return moduleNameTitle+fixName.title()

    def createClassFile(self,fileName,clsName,classStr)->bool:
        """创建类文件
        
        Arguments:
            fileName {[str]} -- [完整的文件路径]
            clsName {[str]} -- [类名]
            classStr {[str]} -- [类文件内容]
        
        Returns:
            bool -- [是否创建成功]
        """
        flag = True
        if os.path.exists(fileName):
            reply = QMessageBox.question(self,"提示","类{0}已经存在，是否覆盖?".format(clsName),QMessageBox.Yes | QMessageBox.No,QMessageBox.No)
            if reply==QMessageBox.Yes:            
                writeFile(fileName,classStr)     
            else:
                flag = False  
        else:
            writeFile(fileName,classStr)
        return flag

    def createModuleFolder(self,folder)->bool:
        """[创建模块文件夹]
        
        Arguments:
            folder {[str]} -- [模块完整路径]
        
        Returns:
            bool -- [是否创建成果]
        """
        isCreateModule = False
        if not os.path.exists(folder): #不存在的模块目录自动创建
            os.makedirs(folder)
            self.appendLog("已为你创建模块 {0} ".format(folder))            
            isCreateModule = True
        return isCreateModule

    def getClickEvtFnStr(self,tempName,displayName,proFix):
        FnTemp = getFnTemp(tempName)
        FnTemp = FnTemp.replace("#","")
        funcStr = self.fmtCaseStr(self.tsInfMap[displayName],proFix)
        funcStr = FnTemp.replace("$case$",funcStr)
        return funcStr

    def fmtCaseStr(self,xmlArr,proFix=""):
        caseStr = ""
        newLine = "\r"        
        for xmlEle in xmlArr:
            caseStr += self.padding*3 + "case this."+self.getFieldName(xmlEle.attr['name'])+proFix+":"+newLine + self.padding*4+"break;"+newLine
        return caseStr

    def getFieldName(self,fieldName):
        """根据xml的属性名生成类的字段名
        
        Arguments:
            fieldName {[type]} -- [description]
        """
        fieldArr = fieldName.split("_")
        flag = getToolCfg(EToolCfg.fieldStyle.name)
        if flag and len(fieldArr)>=2:
            arr = list(map(lambda x: self.getTitleStyle(x),fieldArr))  
            arr[0] = arr[0].lower()
            fieldName = "".join(arr)             
        return fieldName
    
    def xmlToVarFnStr(self,xmlEle):
        """
        根据一个xml节点返回变量定义和初始化组件的代码字符串        
        Arguments:
            xmlEle {[XmlElement]} -- xml节点元素
        """

        varStr = ""
        fnStr = ""        
        proStr = self.proBtn.text()
        varStr = self.padding+proStr+" "+self.getFieldName(xmlEle.attr['name'])+":"+getDataTypeStr(xmlEle.name)+";"
        
        clsTrs = ""
        asVar = ""
        fnSrcStr = ""
        
        clsTrans = "$clsTrans$"
        asVarRegStr = "$asVar$"
        varName = "$name$"
        if xmlEle.name==EDisplayType.controller.name:
            fnSrcStr = 'this.{0}'.format(getFuncName('getController'))+'("{0}")'
        elif self.isBaseList(): #listRender都是通过getChild获得子
            fnSrcStr = 'this.{0}'.format(getFuncName('getChild'))+'("{0}")'        
        else:
            fnSrcStr = 'this.{0}'.format(getFuncName('getGO'))+'("{0}")'
        fnSrcStr = fnSrcStr.format(varName)
        fnSrcStr = clsTrans + fnSrcStr + asVarRegStr
        asVar = getDataVarAs(xmlEle.name)
        if xmlEle.name==EDisplayType.loader.name or isBaseItem(xmlEle):
            clsTrs = asVar
            asVar = ""
        if asVar!="":
            asVar = "."+asVar
        if clsTrs!="":
            clsTrs = "<{0}>".format(clsTrs)
        #print("clsTrs,xmlEle.name",clsTrs,xmlEle.name)
        fnSrcStr = fnSrcStr.replace(varName,xmlEle.attr['name'])
        fnSrcStr = fnSrcStr.replace(clsTrans,clsTrs)
        fnSrcStr = fnSrcStr.replace(asVarRegStr,asVar)

        if xmlEle.name==EDisplayType.list.name:
            fnSrcStr = 'new List({0})'.format(fnSrcStr)
        fnStr = self.padding*2+"this."+self.getFieldName(xmlEle.attr['name'])+" = "+fnSrcStr+";"
        return varStr,fnStr
    
    def getModuleName(self):
        m = "__your_defind__"
        mobj = regModuleName.match(self.searchInput.text())
        if self.isLegalModule():
            m = self.searchInput.text()            
            m = self.getTitleStyle(m)
        return m

    def getTitleStyle(self,srcStr):
        n = len(srcStr)        
        return srcStr[0].upper()+srcStr[1:n]
    def isLegalModule(self):
        """
        是否有效的模块名
        """
        mobj = regModuleName.match(self.searchInput.text())
        return mobj!=None

    def  appendLog(self,msg):
        msg = "<font size='5' >{0}</font>".format(msg)
        self.logText.append(msg)


'''
if __name__ == "__main__":      
    initVersionInf(VERSION_PATH)
    initDataTypeCfg()
    initToolCfg() 
    app = QApplication(sys.argv)    
    panel = TabXMLToTS()   
    panel.show()
    sys.exit(app.exec_())
'''
